package skiree.host.abetsy.service.core.bilibili;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.vdurmont.emoji.EmojiParser;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import skiree.host.abetsy.dao.LocalCommentMapper;
import skiree.host.abetsy.dao.LocalEpisodeMapper;
import skiree.host.abetsy.model.LocalComment;
import skiree.host.abetsy.model.LocalEpisode;
import skiree.host.abetsy.service.core.Stratege;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Component
public class BilibiliProcess implements Stratege {

    @Resource
    private LocalEpisodeMapper localEpisodeMapper;

    @Resource
    private LocalCommentMapper localCommentMapper;

    @Override
    public void loadDanMu(LocalEpisode localEpisodeOld) {
        // 先检查localEpisode状态
        LocalEpisode localEpisode = localEpisodeMapper.selectById(localEpisodeOld.getId());
        if (localEpisode.getStatus().equals("init")) {
            localEpisode.setStatus("loading");
            localEpisode.setTime(new Date());
            localEpisodeMapper.updateById(localEpisode);
            // 开始
            Matcher matcher = Pattern.compile("ep(\\d+)").matcher(localEpisode.getUrl());
            if (matcher.find()) {
                List<LocalComment> comments = new ArrayList<>();
                String ep_id = matcher.group(1);
                String mgUrl = "https://api.bilibili.com/pgc/view/web/season?ep_id=" + ep_id;
                String result = HttpUtil.get(mgUrl, CharsetUtil.CHARSET_UTF_8);
                if (JSONUtil.parseObj(result).getInt("code") == 0) {
                    JSONArray jsonArray = JSONUtil.parseArray(JSONUtil.parse(result).getByPath("$.result.episodes").toString());
                    for (Object object : jsonArray) {
                        JSONObject data = JSONUtil.parseObj(object.toString());
                        String id = data.getStr("id");
                        if (id.equals(ep_id)) {
                            String xmlUrl = "https://comment.bilibili.com/" + data.getStr("cid") + ".xml";
                            String resultXml = HttpUtil.get(xmlUrl, CharsetUtil.CHARSET_UTF_8);
                            Document document = XmlUtil.parseXml(resultXml);
                            NodeList nodeList = document.getElementsByTagName("d");
                            for (int i = 0; i < nodeList.getLength(); i++) {
                                Node node = nodeList.item(i);
                                if (node.getNodeType() == Node.ELEMENT_NODE) {
                                    Element element = (Element) node;
                                    String content = element.getTextContent();
                                    content = EmojiParser.removeAllEmojis(content);
                                    if (!content.isEmpty()) {
                                        double dataStrDou = Double.parseDouble(element.getAttribute("p").split(",")[0]);
                                        BigDecimal start = new BigDecimal(dataStrDou).divide(new BigDecimal(1), 2, RoundingMode.HALF_UP);
                                        if (start.longValue() >= 0){
                                            String time = start.toString();
                                            String style = element.getAttribute("p").split(",")[3];
                                            String position = "1";
                                            String userId = "[bili]";
                                            LocalComment localComment = new LocalComment();
                                            localComment.setEpisodeId(localEpisode.getId());
                                            localComment.setP(String.join(",", Arrays.asList(time, position, style, userId)));
                                            localComment.setM(content);
                                            localComment.setT(start);
                                            comments.add(localComment);
                                        }
                                    }
                                }
                            }

                        }
                    }
                }
                // 时间相同的弹幕只保留三条
                comments = comments.stream()
                        .collect(Collectors.groupingBy(LocalComment::getT))
                        .values().stream()
                        .flatMap(list -> list.stream().limit(3))
                        .collect(Collectors.toList());
                localCommentMapper.insert(comments);
            }
        }
    }

    @Override
    public boolean supports(LocalEpisode localEpisode) {
        return localEpisode.getUrl().contains("bilibili.com");
    }

}